package arrays

import (
	"sync"
)

type IntSet struct {
	m map[int]struct{}
	sync.RWMutex
}

func NewIntSet(items ...int) *IntSet {
	s := &IntSet{
		m: map[int]struct{}{},
	}
	s.Add(items...)
	return s
}

func (s *IntSet) Add(items ...int) {
	s.Lock()
	defer s.Unlock()
	if len(items) == 0 {
		return
	}
	for _, item := range items {
		s.m[item] = struct{}{}
	}
}

func (s *IntSet) Remove(items ...int) {
	s.Lock()
	defer s.Unlock()
	if len(items) == 0 {
		return
	}
	for _, item := range items {
		delete(s.m, item)
	}
}

func (s *IntSet) Has(item int) bool {
	s.RLock()
	defer s.RUnlock()
	_, ok := s.m[item]
	return ok
}

func (s *IntSet) Len() int {
	return len(s.m)
}

func (s *IntSet) Clear() {
	s.Lock()
	defer s.Unlock()
	s.m = map[int]struct{}{}
}

func (s *IntSet) IsEmpty() bool {
	if s.Len() == 0 {
		return true
	}
	return false
}

func (s *IntSet) List() []int {
	s.RLock()
	defer s.RUnlock()
	list := make([]int, 0)
	for item := range s.m {
		list = append(list, item)
	}
	return list
}

// 并集
func (s *IntSet) Union(sets ...*IntSet) *IntSet {
	r := NewIntSet(s.List()...)
	for _, set := range sets {
		for e := range set.m {
			r.m[e] = struct{}{}
		}
	}
	return r
}

// 差集
func (s *IntSet) Minus(sets ...*IntSet) *IntSet {
	r := NewIntSet(s.List()...)
	for _, set := range sets {
		for e := range set.m {
			if _, ok := s.m[e]; ok {
				delete(r.m, e)
			}
		}
	}
	return r
}

// 交集
func (s *IntSet) Intersect(sets ...*IntSet) *IntSet {
	r := NewIntSet(s.List()...)
	for _, set := range sets {
		for e := range s.m {
			if _, ok := set.m[e]; !ok {
				delete(r.m, e)
			}
		}
	}
	return r
}

// 补集
func (s *IntSet) Complement(full *IntSet) *IntSet {
	r := NewIntSet(s.List()...)
	for e := range full.m {
		if _, ok := s.m[e]; !ok {
			r.Add(e)
		}
	}
	return r
}

type StringSet struct {
	m map[string]struct{}
	sync.RWMutex
}

func NewStringSet(items ...string) *StringSet {
	s := &StringSet{
		m: map[string]struct{}{},
	}
	s.Add(items...)
	return s
}

func (s *StringSet) Add(items ...string) {
	s.Lock()
	defer s.Unlock()
	if len(items) == 0 {
		return
	}
	for _, item := range items {
		s.m[item] = struct{}{}
	}
}

func (s *StringSet) Remove(items ...string) {
	s.Lock()
	defer s.Unlock()
	if len(items) == 0 {
		return
	}
	for _, item := range items {
		delete(s.m, item)
	}
}

func (s *StringSet) Has(item string) bool {
	s.RLock()
	defer s.RUnlock()
	_, ok := s.m[item]
	return ok
}

func (s *StringSet) Len() int {
	return len(s.m)
}

func (s *StringSet) Clear() {
	s.Lock()
	defer s.Unlock()
	s.m = map[string]struct{}{}
}

func (s *StringSet) IsEmpty() bool {
	if s.Len() == 0 {
		return true
	}
	return false
}

func (s *StringSet) List() []string {
	s.RLock()
	defer s.RUnlock()
	list := make([]string, 0)
	for item := range s.m {
		list = append(list, item)
	}
	return list
}

// 并集
func (s *StringSet) Union(sets ...*StringSet) *StringSet {
	r := NewStringSet(s.List()...)
	for _, set := range sets {
		for e := range set.m {
			r.m[e] = struct{}{}
		}
	}
	return r
}

// 差集
func (s *StringSet) Minus(sets ...*StringSet) *StringSet {
	r := NewStringSet(s.List()...)
	for _, set := range sets {
		for e := range set.m {
			if _, ok := s.m[e]; ok {
				delete(r.m, e)
			}
		}
	}
	return r
}

// 交集
func (s *StringSet) Intersect(sets ...*StringSet) *StringSet {
	r := NewStringSet(s.List()...)
	for _, set := range sets {
		for e := range s.m {
			if _, ok := set.m[e]; !ok {
				delete(r.m, e)
			}
		}
	}
	return r
}

// 补集
func (s *StringSet) Complement(full *StringSet) *StringSet {
	r := NewStringSet(s.List()...)
	for e := range full.m {
		if _, ok := s.m[e]; !ok {
			r.Add(e)
		}
	}
	return r
}